#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
#include "task.hpp"

#define NUM 5

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int pipe_num = 0;
class channel
{
public:
    channel(int _fd, pid_t _id) : fd(_fd), id(_id)
    {
        name = "channel:" + std::to_string(pipe_num++);
    }
    string name;
    pid_t id;
    int fd; // 文件描述符
};

void work()
{
    int code = 0;
    while (true)
    {
        ssize_t n = read(0, &code, sizeof(code)); // 从管道中读出需要执行的任务
        if (n == sizeof(code))
        {
            if (init.CheckCode(code)) // 检测任务是否合法，是否越界
            {
                init.RunTask(code); // 运行
            }
        }
        else if (n == 0) // n==0说明父进程写端以及关闭，那么此时可以退出程序
        {
            break;
        }
        else
        {
            // do nothing
        }
        sleep(1);
    }
}

void createchannels(vector<channel> *_channel)
{
    vector<int> pipefds;
    for (int i = 0; i < NUM; i++)
    {
        int pipefd[2];
        int ret = pipe(pipefd);
        if (ret < 0)
        {
            perror("pipe error!");
            assert(ret < 0);
        }
        // pipefds.push_back(pipefd[1]); //将父进程打开的写短记录下来，方便后续子进程关闭

        pid_t id = fork();
        assert(id != -1);

        if (id == 0) // 子进程,对管道只读
        {
            cout << "create thread! ppid:" << getppid() << "  pid:" << getpid()
                 << "fd[0]:" << pipefd[0] << "  fd[1]:" << pipefd[1] << endl;
            for (auto &e : pipefds)
                close(e); // 关闭子进程的写端

            close(pipefd[1]);
            dup2(pipefd[0], 0); // 将子进程的pipefd[0]重定向到标准输入，之后直接从标准输入中读取任务即可
            // 但也可以通过传参的方式进行

            work();

            exit(0);
        }

        close(pipefd[0]);             // 每次关闭父进程读
        pipefds.push_back(pipefd[1]); // 记录当前的写端，下一个子进程需要关闭该写端

        _channel->push_back(channel(pipefd[1], id)); // 记录每个进程的相关数据，备用

        sleep(1);
    }
}

void sendcommand(vector<channel> &channels, bool flag, int num = -1)
{
    int pos = 0, size = channels.size();
    while (true)
    {
        int n = init.SendTask();
        auto &e = channels[pos++];

        write(e.fd, &n, sizeof(n));

        pos %= size;

        if (!flag && num-- == 0)
            break;

        cout << "sendcommand succeed! --" <<init.Todesc(n) << endl;
        sleep(1); // 每隔一秒发送一个任务
    }
    cout << "stop sendcommand!" << endl;
}

void realsecommand(vector<channel> &channels)
{
    for (auto &e : channels)
    {

        close(e.fd); // 关闭父进程的写端
        waitpid(e.id, nullptr, 0);
        cout << "channel:" << e.id << "close!" << endl;
    }
}

int main()
{
    vector<channel> channels;  
    
    createchannels(&channels);

    bool _command_flag = 0;

    sendcommand(channels, _command_flag, 10); // 发送任务

    realsecommand(channels);
}
